// Decompiled on 周六 2月 22 19:31:49 CST 2025 with Zomboid Decompiler v0.1.3 using Vineflower.
package zombie.network;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import zombie.characters.IsoPlayer;
import zombie.core.logger.ExceptionLogger;
import zombie.core.network.ByteBufferWriter;
import zombie.core.raknet.UdpConnection;
import zombie.debug.DebugLog;
import zombie.network.packets.PlayerPacket;

public class ReplayManager {
    private static final int ReplayManagerVersion = 1;
    private ReplayManager.State state = ReplayManager.State.Stop;
    private IsoPlayer player = null;
    private ByteBuffer bbpp = ByteBuffer.allocate(43);
    private FileOutputStream outStream = null;
    private DataOutputStream output = null;
    private FileInputStream inStream = null;
    private DataInputStream input = null;
    private int inputVersion = 0;
    private long inputTimeShift = 0L;
    private PlayerPacket nextpp = null;
    private long nextppTime = 0L;

    public ReplayManager(IsoPlayer _player) {
        this.player = _player;
    }

    public ReplayManager.State getState() {
        return this.state;
    }

    public boolean isPlay() {
        return this.state == ReplayManager.State.Playing;
    }

    public void recordPlayerPacket(PlayerPacket pp) {
        if (this.state == ReplayManager.State.Recording && pp.id == this.player.OnlineID) {
            this.bbpp.position(0);
            ByteBufferWriter byteBufferWriter = new ByteBufferWriter(this.bbpp);
            pp.write(byteBufferWriter);

            try {
                this.output.writeLong(zombie.GameTime.getServerTime());
                this.output.write(PacketTypes.PacketType.PlayerUpdate.getId());
                this.output.write(byteBufferWriter.bb.array());
            } catch (IOException iOException) {
                iOException.printStackTrace();
            }
        }
    }

    public boolean startRecordReplay(IsoPlayer _player, String filename) {
        File file = zombie.ZomboidFileSystem.instance.getFileInCurrentSave(filename);
        if (this.player != null && this.state == ReplayManager.State.Recording) {
            DebugLog.log("ReplayManager: record replay already active for " + this.player.getUsername() + " user");
            return false;
        } else if (file.exists()) {
            DebugLog.log("ReplayManager: invalid filename \"" + filename + "\"");
            return false;
        } else {
            try {
                this.outStream = new FileOutputStream(file);
                this.output = new DataOutputStream(this.outStream);
                this.output.write(1);
                this.output.writeLong(zombie.GameTime.getServerTime());
                this.player = _player;
                this.state = ReplayManager.State.Recording;
                return true;
            } catch (Exception exception) {
                ExceptionLogger.logException(exception);
                return false;
            }
        }
    }

    public boolean stopRecordReplay() {
        if (this.state != ReplayManager.State.Recording) {
            DebugLog.log("ReplayManager: record inactive");
            return false;
        } else {
            try {
                this.state = ReplayManager.State.Stop;
                this.player = null;
                this.output.flush();
                this.output.close();
                this.outStream.close();
                this.output = null;
                return true;
            } catch (IOException iOException) {
                iOException.printStackTrace();
                return false;
            }
        }
    }

    public boolean startPlayReplay(IsoPlayer _player, String filename, UdpConnection connection) {
        File file = zombie.ZomboidFileSystem.instance.getFileInCurrentSave(filename);
        if (this.state == ReplayManager.State.Playing) {
            DebugLog.log("ReplayManager: play replay already active for " + this.player.getUsername() + " user");
            return false;
        } else if (!file.exists()) {
            DebugLog.log("ReplayManager: invalid filename \"" + filename + "\"");
            return false;
        } else {
            try {
                this.inStream = new FileInputStream(file);
                this.input = new DataInputStream(this.inStream);
                this.inputVersion = this.input.read();
                this.inputTimeShift = zombie.GameTime.getServerTime() - this.input.readLong();
                this.nextppTime = this.input.readLong();
                int _int = this.input.read();
                if (_int == PacketTypes.PacketType.PlayerUpdate.getId() || _int == PacketTypes.PacketType.PlayerUpdateReliable.getId()) {
                    this.input.read(this.bbpp.array());
                    this.bbpp.position(0);
                    this.nextpp = new PlayerPacket();
                    this.nextpp.parse(this.bbpp, connection);
                }

                this.player = _player;
                this.state = ReplayManager.State.Playing;
                return true;
            } catch (Exception exception) {
                ExceptionLogger.logException(exception);
                return false;
            }
        }
    }

    public boolean stopPlayReplay() {
        if (this.state != ReplayManager.State.Playing) {
            DebugLog.log("ReplayManager: play inactive");
            return false;
        } else {
            try {
                this.state = ReplayManager.State.Stop;
                this.player = null;
                this.input.close();
                this.inStream.close();
                this.input = null;
                this.inputVersion = 0;
                this.inputTimeShift = 0L;
                this.nextpp = null;
                return true;
            } catch (IOException iOException) {
                iOException.printStackTrace();
                return false;
            }
        }
    }

    public void update() {
        if (this.state == ReplayManager.State.Playing) {
            if (zombie.GameTime.getServerTime() >= this.nextppTime + this.inputTimeShift) {
                this.nextpp.id = this.player.OnlineID;
                this.nextpp.realt = (int)((long)this.nextpp.realt + this.inputTimeShift / 1000000L);
                IsoPlayer isoPlayer = (IsoPlayer)GameServer.IDToPlayerMap.get(Integer.valueOf(this.nextpp.id));
                UdpConnection udpConnection0 = GameServer.getConnectionFromPlayer(isoPlayer);

                try {
                    if (isoPlayer == null) {
                        DebugLog.General
                            .error(
                                "receivePlayerUpdate: Server received position for unknown player (id:" + this.nextpp.id + "). Server will ignore this data."
                            );
                    } else {
                        isoPlayer.networkAI.parse(this.nextpp);
                        udpConnection0.ReleventPos[isoPlayer.PlayerIndex].x = this.nextpp.realx;
                        udpConnection0.ReleventPos[isoPlayer.PlayerIndex].y = this.nextpp.realy;
                        udpConnection0.ReleventPos[isoPlayer.PlayerIndex].z = (float)this.nextpp.realz;
                    }
                } catch (Exception exception) {
                    exception.printStackTrace();
                }

                for (int int0 = 0; int0 < GameServer.udpEngine.connections.size(); int0++) {
                    UdpConnection udpConnection1 = (UdpConnection)GameServer.udpEngine.connections.get(int0);
                    if (udpConnection0.getConnectedGUID() != udpConnection1.getConnectedGUID()) {
                        ByteBufferWriter byteBufferWriter = udpConnection1.startPacket();
                        PacketTypes.PacketType.PlayerUpdate.doPacket(byteBufferWriter);
                        this.nextpp.write(byteBufferWriter);
                        PacketTypes.PacketType.PlayerUpdate.send(udpConnection1);
                    }
                }

                try {
                    this.nextppTime = this.input.readLong();
                    int int1 = this.input.read();
                    if (int1 == PacketTypes.PacketType.PlayerUpdate.getId() || int1 == PacketTypes.PacketType.PlayerUpdateReliable.getId()) {
                        this.bbpp.position(0);
                        this.input.read(this.bbpp.array());
                        this.bbpp.position(0);
                        this.nextpp = new PlayerPacket();
                        this.nextpp.parse(this.bbpp, udpConnection0);
                    }
                } catch (IOException iOException) {
                    DebugLog.log("ReplayManager: stop playing replay");
                    this.stopPlayReplay();
                }
            }
        }
    }

    public static enum State {
        Stop,
        Recording,
        Playing;
    }
}
